{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tutorial 3 - Benchmarks\n",
    "\n",
    "In this tutorial, we will give you some hints on how to benchmark you homomorphic encryption application, and choose the best suited parameters.\n",
    "\n",
    "We recommend checking out the other tutorials first:\n",
    "- ['Tutorial 0 - Getting Started'](https://github.com/OpenMined/TenSEAL/blob/master/tutorials/Tutorial%200%20-%20Getting%20Started.ipynb).\n",
    "- ['Tutorial 1: Training and Evaluation of Logistic Regression on Encrypted Data'](https://github.com/OpenMined/TenSEAL/blob/master/tutorials/Tutorial%201%20-%20Training%20and%20Evaluation%20of%20Logistic%20Regression%20on%20Encrypted%20Data.ipynb).\n",
    "\n",
    "Authors:\n",
    "- Bogdan Cebere - Twitter: [@bcebere](https://twitter.com/bcebere)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introduction\n",
    "\n",
    "\n",
    "\n",
    "TenSEAL is a library for doing homomorphic encryption operations on tensors. It's built on top of [Microsoft SEAL](https://github.com/Microsoft/SEAL), a C++ library implementing the BFV and CKKS homomorphic encryption schemes.\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Homomorphic Encryption Parameters Review\n",
    "\n",
    "#### The scaling factor(CKKS)\n",
    "The first step of the CKKS scheme is encoding a vector of real numbers into a plaintext polynomial.\n",
    "\n",
    "\n",
    "The scaling factor defines the encoding precision for the binary representation of the number. Intuitively, we are talking about binary precision as pictured below:\n",
    "\n",
    "\n",
    "<img src=\"assets/floating_point.png\" alt=\"ckks-high-level\" width=\"400\"/>\n",
    "\n",
    "#### The polynomial modulus degree (poly_modulus_degree)\n",
    "\n",
    "The polynomial modulus($N$ in the diagram) directly affects:\n",
    " - The number of coefficients in plaintext polynomials\n",
    " - The size of ciphertext elements\n",
    " - The computational performance of the scheme (bigger is worse)\n",
    " - The security level (bigger is better).\n",
    "\n",
    "In TenSEAL, as in Microsoft SEAL, the degree of the polynomial modulus must be a power of 2 (e.g. $1024$, $2048$, $4096$, $8192$, $16384$, or $32768$).\n",
    "\n",
    "#### The coefficient modulus sizes\n",
    "\n",
    "The last parameter required for the scheme is a list of binary sizes.\n",
    "Using this list, SEAL will generate a list of primes of those binary sizes, called the coefficient modulus($q$ in the diagram).\n",
    "\n",
    "The coefficient modulus directly affects:\n",
    " - The size of ciphertext elements\n",
    " - The length of the list indicates the level of the scheme(or the number of encrypted multiplications supported).\n",
    " - The security level (bigger is worse).\n",
    " \n",
    "In TenSEAL, as in Microsoft SEAL, each of the prime numbers in the coefficient modulus must be at most 60 bits and must be congruent to 1 modulo 2*poly_modulus_degree."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setup "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: tabulate in /home/bcebere/anaconda3/envs/tenseal/lib/python3.8/site-packages (0.8.7)\r\n"
     ]
    }
   ],
   "source": [
    "!pip install tabulate\n",
    "\n",
    "import tenseal as ts\n",
    "import tenseal.sealapi as seal\n",
    "import random\n",
    "import pickle\n",
    "import numpy as np\n",
    "import math\n",
    "from IPython.display import HTML, display\n",
    "import tabulate\n",
    "import pytest\n",
    " \n",
    "def convert_size(size_bytes):\n",
    "    if size_bytes == 0:\n",
    "        return \"0B\"\n",
    "    size_name = (\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\")\n",
    "    i = int(math.floor(math.log(size_bytes, 1024)))\n",
    "    p = math.pow(1024, i)\n",
    "    s = round(size_bytes / p, 2)\n",
    "    return \"%s %s\" % (s, size_name[i])\n",
    "\n",
    "enc_type_str = {\n",
    "    ts.ENCRYPTION_TYPE.SYMMETRIC : \"symmetric\", \n",
    "    ts.ENCRYPTION_TYPE.ASYMMETRIC : \"asymmetric\",\n",
    "}\n",
    "\n",
    "scheme_str = {\n",
    "    ts.SCHEME_TYPE.CKKS : \"ckks\", \n",
    "    ts.SCHEME_TYPE.BFV : \"bfv\",\n",
    "}\n",
    "\n",
    "def decrypt(enc):\n",
    "    return enc.decrypt()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Context serialization\n",
    "\n",
    "\n",
    "The TenSEAL context is required for defining the performance and security of your application.\n",
    "\n",
    "In a client-server setup, it is required only on the initial handshake, as the ciphertexts can be linked with an existing context on deserialization.\n",
    "\n",
    "Here we are benchmarking the size of the context, depending on the input parameters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table>\n",
       "<tbody>\n",
       "<tr><td>Encryption Type</td><td>Scheme Type</td><td>Polynomial modulus</td><td>Coefficient modulus sizes       </td><td>Saved keys </td><td>Context serialized size</td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>all        </td><td>263.02 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>Secret key </td><td>263.02 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>Galois keys</td><td>86.87 MB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>Relin keys </td><td>3.63 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>none       </td><td>112.0 B                </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[40, 20, 40]                    </td><td>all        </td><td>124.71 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[40, 20, 40]                    </td><td>Secret key </td><td>124.71 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[40, 20, 40]                    </td><td>Galois keys</td><td>11.89 MB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[40, 20, 40]                    </td><td>Relin keys </td><td>503.79 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[40, 20, 40]                    </td><td>none       </td><td>91.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[20, 20, 20]                    </td><td>all        </td><td>79.39 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[20, 20, 20]                    </td><td>Secret key </td><td>79.38 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[20, 20, 20]                    </td><td>Galois keys</td><td>7.48 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[20, 20, 20]                    </td><td>Relin keys </td><td>317.27 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[20, 20, 20]                    </td><td>none       </td><td>85.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[17, 17]                        </td><td>all        </td><td>44.21 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[17, 17]                        </td><td>Secret key </td><td>44.2 KB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[17, 17]                        </td><td>Galois keys</td><td>2.15 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[17, 17]                        </td><td>Relin keys </td><td>86.67 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>8192              </td><td>[17, 17]                        </td><td>none       </td><td>80.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[40, 20, 40]                    </td><td>all        </td><td>62.57 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[40, 20, 40]                    </td><td>Secret key </td><td>62.56 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[40, 20, 40]                    </td><td>Galois keys</td><td>5.48 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[40, 20, 40]                    </td><td>Relin keys </td><td>253.28 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[40, 20, 40]                    </td><td>none       </td><td>92.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[30, 20, 30]                    </td><td>all        </td><td>51.1 KB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[30, 20, 30]                    </td><td>Secret key </td><td>51.09 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[30, 20, 30]                    </td><td>Galois keys</td><td>4.53 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[30, 20, 30]                    </td><td>Relin keys </td><td>208.5 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[30, 20, 30]                    </td><td>none       </td><td>95.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[20, 20, 20]                    </td><td>all        </td><td>40.0 KB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[20, 20, 20]                    </td><td>Secret key </td><td>39.99 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[20, 20, 20]                    </td><td>Galois keys</td><td>3.44 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[20, 20, 20]                    </td><td>Relin keys </td><td>159.37 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[20, 20, 20]                    </td><td>none       </td><td>84.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[19, 19, 19]                    </td><td>all        </td><td>37.83 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[19, 19, 19]                    </td><td>Secret key </td><td>37.83 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[19, 19, 19]                    </td><td>Galois keys</td><td>3.3 MB                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[19, 19, 19]                    </td><td>Relin keys </td><td>150.98 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[19, 19, 19]                    </td><td>none       </td><td>84.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[18, 18, 18]                    </td><td>all        </td><td>35.63 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[18, 18, 18]                    </td><td>Secret key </td><td>35.62 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[18, 18, 18]                    </td><td>Galois keys</td><td>3.15 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[18, 18, 18]                    </td><td>Relin keys </td><td>143.23 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[18, 18, 18]                    </td><td>none       </td><td>83.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[18, 18]                        </td><td>all        </td><td>24.04 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[18, 18]                        </td><td>Secret key </td><td>24.04 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[18, 18]                        </td><td>Galois keys</td><td>1.05 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[18, 18]                        </td><td>Relin keys </td><td>47.62 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[18, 18]                        </td><td>none       </td><td>78.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[17, 17]                        </td><td>all        </td><td>21.89 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[17, 17]                        </td><td>Secret key </td><td>21.89 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[17, 17]                        </td><td>Galois keys</td><td>1004.95 KB             </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[17, 17]                        </td><td>Relin keys </td><td>43.88 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>4096              </td><td>[17, 17]                        </td><td>none       </td><td>80.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>2048              </td><td>[20, 20]                        </td><td>all        </td><td>13.18 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>2048              </td><td>[20, 20]                        </td><td>Secret key </td><td>13.18 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>2048              </td><td>[20, 20]                        </td><td>Galois keys</td><td>532.83 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>2048              </td><td>[20, 20]                        </td><td>Relin keys </td><td>26.68 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>2048              </td><td>[20, 20]                        </td><td>none       </td><td>80.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>2048              </td><td>[18, 18]                        </td><td>all        </td><td>12.36 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>2048              </td><td>[18, 18]                        </td><td>Secret key </td><td>12.35 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>2048              </td><td>[18, 18]                        </td><td>Galois keys</td><td>495.28 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>2048              </td><td>[18, 18]                        </td><td>Relin keys </td><td>24.57 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>2048              </td><td>[18, 18]                        </td><td>none       </td><td>79.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>2048              </td><td>[16, 16]                        </td><td>all        </td><td>9.21 KB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>2048              </td><td>[16, 16]                        </td><td>Secret key </td><td>9.21 KB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>2048              </td><td>[16, 16]                        </td><td>Galois keys</td><td>417.42 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>2048              </td><td>[16, 16]                        </td><td>Relin keys </td><td>19.03 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>ckks       </td><td>2048              </td><td>[16, 16]                        </td><td>none       </td><td>79.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>all        </td><td>263.54 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>Secret key </td><td>263.53 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>Galois keys</td><td>86.88 MB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>Relin keys </td><td>3.63 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>none       </td><td>111.0 B                </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 40]    </td><td>all        </td><td>234.87 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 40]    </td><td>Secret key </td><td>234.87 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 40]    </td><td>Galois keys</td><td>66.86 MB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 40]    </td><td>Relin keys </td><td>2.78 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 40]    </td><td>none       </td><td>106.0 B                </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 40]        </td><td>all        </td><td>209.74 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 40]        </td><td>Secret key </td><td>209.73 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 40]        </td><td>Galois keys</td><td>49.34 MB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 40]        </td><td>Relin keys </td><td>2.06 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 40]        </td><td>none       </td><td>103.0 B                </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 40]            </td><td>all        </td><td>179.06 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 40]            </td><td>Secret key </td><td>179.05 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 40]            </td><td>Galois keys</td><td>34.35 MB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 40]            </td><td>Relin keys </td><td>1.42 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 40]            </td><td>none       </td><td>99.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 40]                </td><td>all        </td><td>154.96 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 40]                </td><td>Secret key </td><td>154.95 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 40]                </td><td>Galois keys</td><td>21.89 MB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 40]                </td><td>Relin keys </td><td>936.54 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 40]                </td><td>none       </td><td>94.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 20, 40]                    </td><td>all        </td><td>124.87 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 20, 40]                    </td><td>Secret key </td><td>124.86 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 20, 40]                    </td><td>Galois keys</td><td>11.89 MB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 20, 40]                    </td><td>Relin keys </td><td>503.81 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>8192              </td><td>[40, 20, 40]                    </td><td>none       </td><td>90.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[40, 20, 40]                    </td><td>all        </td><td>62.54 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[40, 20, 40]                    </td><td>Secret key </td><td>62.54 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[40, 20, 40]                    </td><td>Galois keys</td><td>5.48 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[40, 20, 40]                    </td><td>Relin keys </td><td>253.28 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[40, 20, 40]                    </td><td>none       </td><td>91.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[30, 20, 30]                    </td><td>all        </td><td>50.54 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[30, 20, 30]                    </td><td>Secret key </td><td>50.54 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[30, 20, 30]                    </td><td>Galois keys</td><td>4.53 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[30, 20, 30]                    </td><td>Relin keys </td><td>208.44 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[30, 20, 30]                    </td><td>none       </td><td>94.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[20, 20, 20]                    </td><td>all        </td><td>40.06 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[20, 20, 20]                    </td><td>Secret key </td><td>40.06 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[20, 20, 20]                    </td><td>Galois keys</td><td>3.44 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[20, 20, 20]                    </td><td>Relin keys </td><td>159.22 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[20, 20, 20]                    </td><td>none       </td><td>89.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[19, 19, 19]                    </td><td>all        </td><td>37.8 KB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[19, 19, 19]                    </td><td>Secret key </td><td>37.79 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[19, 19, 19]                    </td><td>Galois keys</td><td>3.3 MB                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[19, 19, 19]                    </td><td>Relin keys </td><td>151.13 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[19, 19, 19]                    </td><td>none       </td><td>89.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[18, 18, 18]                    </td><td>all        </td><td>35.62 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[18, 18, 18]                    </td><td>Secret key </td><td>35.62 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[18, 18, 18]                    </td><td>Galois keys</td><td>3.16 MB                </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[18, 18, 18]                    </td><td>Relin keys </td><td>143.16 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>4096              </td><td>[18, 18, 18]                    </td><td>none       </td><td>88.0 B                 </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>2048              </td><td>[20, 20]                        </td><td>all        </td><td>13.14 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>2048              </td><td>[20, 20]                        </td><td>Secret key </td><td>13.13 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>2048              </td><td>[20, 20]                        </td><td>Galois keys</td><td>532.93 KB              </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>2048              </td><td>[20, 20]                        </td><td>Relin keys </td><td>26.92 KB               </td></tr>\n",
       "<tr><td>symmetric      </td><td>bfv        </td><td>2048              </td><td>[20, 20]                        </td><td>none       </td><td>85.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>all        </td><td>790.25 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>Public key </td><td>527.44 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>Secret key </td><td>262.92 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>Galois keys</td><td>86.88 MB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>Relin keys </td><td>3.63 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>none       </td><td>110.0 B                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 20, 40]                    </td><td>all        </td><td>376.41 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 20, 40]                    </td><td>Public key </td><td>251.69 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 20, 40]                    </td><td>Secret key </td><td>124.8 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 20, 40]                    </td><td>Galois keys</td><td>11.89 MB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 20, 40]                    </td><td>Relin keys </td><td>504.68 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 20, 40]                    </td><td>none       </td><td>89.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[20, 20, 20]                    </td><td>all        </td><td>237.66 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[20, 20, 20]                    </td><td>Public key </td><td>158.45 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[20, 20, 20]                    </td><td>Secret key </td><td>79.28 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[20, 20, 20]                    </td><td>Galois keys</td><td>7.48 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[20, 20, 20]                    </td><td>Relin keys </td><td>317.52 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[20, 20, 20]                    </td><td>none       </td><td>83.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[17, 17]                        </td><td>all        </td><td>129.95 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[17, 17]                        </td><td>Public key </td><td>87.24 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[17, 17]                        </td><td>Secret key </td><td>42.78 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[17, 17]                        </td><td>Galois keys</td><td>2.15 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[17, 17]                        </td><td>Relin keys </td><td>85.84 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[17, 17]                        </td><td>none       </td><td>78.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[40, 20, 40]                    </td><td>all        </td><td>188.88 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[40, 20, 40]                    </td><td>Public key </td><td>126.19 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[40, 20, 40]                    </td><td>Secret key </td><td>62.78 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[40, 20, 40]                    </td><td>Galois keys</td><td>5.48 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[40, 20, 40]                    </td><td>Relin keys </td><td>253.2 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[40, 20, 40]                    </td><td>none       </td><td>90.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[30, 20, 30]                    </td><td>all        </td><td>153.89 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[30, 20, 30]                    </td><td>Public key </td><td>103.44 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[30, 20, 30]                    </td><td>Secret key </td><td>50.54 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[30, 20, 30]                    </td><td>Galois keys</td><td>4.53 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[30, 20, 30]                    </td><td>Relin keys </td><td>208.52 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[30, 20, 30]                    </td><td>none       </td><td>93.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[20, 20, 20]                    </td><td>all        </td><td>119.78 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[20, 20, 20]                    </td><td>Public key </td><td>79.65 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[20, 20, 20]                    </td><td>Secret key </td><td>40.2 KB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[20, 20, 20]                    </td><td>Galois keys</td><td>3.44 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[20, 20, 20]                    </td><td>Relin keys </td><td>159.35 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[20, 20, 20]                    </td><td>none       </td><td>82.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[19, 19, 19]                    </td><td>all        </td><td>113.22 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[19, 19, 19]                    </td><td>Public key </td><td>75.5 KB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[19, 19, 19]                    </td><td>Secret key </td><td>37.79 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[19, 19, 19]                    </td><td>Galois keys</td><td>3.3 MB                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[19, 19, 19]                    </td><td>Relin keys </td><td>150.93 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[19, 19, 19]                    </td><td>none       </td><td>82.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[18, 18, 18]                    </td><td>all        </td><td>106.65 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[18, 18, 18]                    </td><td>Public key </td><td>70.97 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[18, 18, 18]                    </td><td>Secret key </td><td>35.75 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[18, 18, 18]                    </td><td>Galois keys</td><td>3.15 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[18, 18, 18]                    </td><td>Relin keys </td><td>143.25 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[18, 18, 18]                    </td><td>none       </td><td>81.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[18, 18]                        </td><td>all        </td><td>71.57 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[18, 18]                        </td><td>Public key </td><td>47.68 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[18, 18]                        </td><td>Secret key </td><td>23.97 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[18, 18]                        </td><td>Galois keys</td><td>1.05 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[18, 18]                        </td><td>Relin keys </td><td>47.7 KB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[18, 18]                        </td><td>none       </td><td>76.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[17, 17]                        </td><td>all        </td><td>65.95 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[17, 17]                        </td><td>Public key </td><td>44.26 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[17, 17]                        </td><td>Secret key </td><td>21.76 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[17, 17]                        </td><td>Galois keys</td><td>1005.05 KB             </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[17, 17]                        </td><td>Relin keys </td><td>43.96 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[17, 17]                        </td><td>none       </td><td>78.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[20, 20]                        </td><td>all        </td><td>39.77 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[20, 20]                        </td><td>Public key </td><td>26.58 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[20, 20]                        </td><td>Secret key </td><td>13.26 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[20, 20]                        </td><td>Galois keys</td><td>532.55 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[20, 20]                        </td><td>Relin keys </td><td>26.88 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[20, 20]                        </td><td>none       </td><td>78.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[18, 18]                        </td><td>all        </td><td>36.88 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[18, 18]                        </td><td>Public key </td><td>24.65 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[18, 18]                        </td><td>Secret key </td><td>12.3 KB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[18, 18]                        </td><td>Galois keys</td><td>495.19 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[18, 18]                        </td><td>Relin keys </td><td>24.62 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[18, 18]                        </td><td>none       </td><td>77.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[16, 16]                        </td><td>all        </td><td>28.24 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[16, 16]                        </td><td>Public key </td><td>18.52 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[16, 16]                        </td><td>Secret key </td><td>9.79 KB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[16, 16]                        </td><td>Galois keys</td><td>416.98 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[16, 16]                        </td><td>Relin keys </td><td>19.02 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[16, 16]                        </td><td>none       </td><td>77.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>all        </td><td>792.25 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>Public key </td><td>528.53 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>Secret key </td><td>263.81 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>Galois keys</td><td>86.87 MB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>Relin keys </td><td>3.63 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>none       </td><td>109.0 B                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 40]    </td><td>all        </td><td>706.98 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 40]    </td><td>Public key </td><td>471.95 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 40]    </td><td>Secret key </td><td>235.13 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 40]    </td><td>Galois keys</td><td>66.85 MB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 40]    </td><td>Relin keys </td><td>2.78 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 40]    </td><td>none       </td><td>104.0 B                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 40]        </td><td>all        </td><td>628.53 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 40]        </td><td>Public key </td><td>419.28 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 40]        </td><td>Secret key </td><td>209.34 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 40]        </td><td>Galois keys</td><td>49.34 MB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 40]        </td><td>Relin keys </td><td>2.06 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 40]        </td><td>none       </td><td>101.0 B                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 40]            </td><td>all        </td><td>543.08 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 40]            </td><td>Public key </td><td>362.33 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 40]            </td><td>Secret key </td><td>180.84 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 40]            </td><td>Galois keys</td><td>34.35 MB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 40]            </td><td>Relin keys </td><td>1.42 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 40]            </td><td>none       </td><td>97.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 40]                </td><td>all        </td><td>463.22 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 40]                </td><td>Public key </td><td>309.94 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 40]                </td><td>Secret key </td><td>153.37 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 40]                </td><td>Galois keys</td><td>21.89 MB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 40]                </td><td>Relin keys </td><td>936.02 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 40]                </td><td>none       </td><td>92.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 20, 40]                    </td><td>all        </td><td>375.43 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 20, 40]                    </td><td>Public key </td><td>250.67 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 20, 40]                    </td><td>Secret key </td><td>124.84 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 20, 40]                    </td><td>Galois keys</td><td>11.89 MB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 20, 40]                    </td><td>Relin keys </td><td>503.74 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 20, 40]                    </td><td>none       </td><td>88.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[40, 20, 40]                    </td><td>all        </td><td>188.93 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[40, 20, 40]                    </td><td>Public key </td><td>126.23 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[40, 20, 40]                    </td><td>Secret key </td><td>62.78 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[40, 20, 40]                    </td><td>Galois keys</td><td>5.48 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[40, 20, 40]                    </td><td>Relin keys </td><td>253.05 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[40, 20, 40]                    </td><td>none       </td><td>89.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[30, 20, 30]                    </td><td>all        </td><td>154.31 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[30, 20, 30]                    </td><td>Public key </td><td>103.4 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[30, 20, 30]                    </td><td>Secret key </td><td>50.99 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[30, 20, 30]                    </td><td>Galois keys</td><td>4.53 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[30, 20, 30]                    </td><td>Relin keys </td><td>208.41 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[30, 20, 30]                    </td><td>none       </td><td>92.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[20, 20, 20]                    </td><td>all        </td><td>119.6 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[20, 20, 20]                    </td><td>Public key </td><td>79.71 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[20, 20, 20]                    </td><td>Secret key </td><td>39.97 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[20, 20, 20]                    </td><td>Galois keys</td><td>3.44 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[20, 20, 20]                    </td><td>Relin keys </td><td>159.17 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[20, 20, 20]                    </td><td>none       </td><td>87.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[19, 19, 19]                    </td><td>all        </td><td>113.17 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[19, 19, 19]                    </td><td>Public key </td><td>75.45 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[19, 19, 19]                    </td><td>Secret key </td><td>37.81 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[19, 19, 19]                    </td><td>Galois keys</td><td>3.3 MB                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[19, 19, 19]                    </td><td>Relin keys </td><td>151.06 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[19, 19, 19]                    </td><td>none       </td><td>87.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[18, 18, 18]                    </td><td>all        </td><td>106.65 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[18, 18, 18]                    </td><td>Public key </td><td>71.16 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[18, 18, 18]                    </td><td>Secret key </td><td>35.58 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[18, 18, 18]                    </td><td>Galois keys</td><td>3.15 MB                </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[18, 18, 18]                    </td><td>Relin keys </td><td>143.09 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[18, 18, 18]                    </td><td>none       </td><td>86.0 B                 </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>2048              </td><td>[20, 20]                        </td><td>all        </td><td>39.83 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>2048              </td><td>[20, 20]                        </td><td>Public key </td><td>26.74 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>2048              </td><td>[20, 20]                        </td><td>Secret key </td><td>13.17 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>2048              </td><td>[20, 20]                        </td><td>Galois keys</td><td>532.93 KB              </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>2048              </td><td>[20, 20]                        </td><td>Relin keys </td><td>26.63 KB               </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>2048              </td><td>[20, 20]                        </td><td>none       </td><td>83.0 B                 </td></tr>\n",
       "</tbody>\n",
       "</table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "ctx_size_benchmarks = [[\"Encryption Type\", \"Scheme Type\", \"Polynomial modulus\", \"Coefficient modulus sizes\", \"Saved keys\", \"Context serialized size\", ]]\n",
    "\n",
    "for enc_type in [ts.ENCRYPTION_TYPE.SYMMETRIC, ts.ENCRYPTION_TYPE.ASYMMETRIC]:\n",
    "    for (poly_mod, coeff_mod_bit_sizes) in [\n",
    "        (8192, [40, 21, 21, 21, 21, 21, 21, 40]),\n",
    "        (8192, [40, 20, 40]),\n",
    "        (8192, [20, 20, 20]),\n",
    "        (8192, [17, 17]),\n",
    "        (4096, [40, 20, 40]),\n",
    "        (4096, [30, 20, 30]),\n",
    "        (4096, [20, 20, 20]),\n",
    "        (4096, [19, 19, 19]),\n",
    "        (4096, [18, 18, 18]),\n",
    "        (4096, [18, 18]),\n",
    "        (4096, [17, 17]),\n",
    "        (2048, [20, 20]),\n",
    "        (2048, [18, 18]),\n",
    "        (2048, [16, 16]),\n",
    "    ]:\n",
    "        context = ts.context(\n",
    "            scheme=ts.SCHEME_TYPE.CKKS,\n",
    "            poly_modulus_degree=poly_mod,\n",
    "            coeff_mod_bit_sizes=coeff_mod_bit_sizes,\n",
    "            encryption_type=enc_type,\n",
    "        )\n",
    "        context.generate_galois_keys()\n",
    "        context.generate_relin_keys()\n",
    "        \n",
    "        ser = context.serialize(save_public_key=True, save_secret_key=True, save_galois_keys=True, save_relin_keys=True)\n",
    "        ctx_size_benchmarks.append([enc_type_str[enc_type], scheme_str[ts.SCHEME_TYPE.CKKS], poly_mod, coeff_mod_bit_sizes, \"all\", convert_size(len(ser))])\n",
    "        \n",
    "        if enc_type is ts.ENCRYPTION_TYPE.ASYMMETRIC:\n",
    "            ser = context.serialize(save_public_key=True, save_secret_key=False, save_galois_keys=False, save_relin_keys=False)\n",
    "            ctx_size_benchmarks.append([enc_type_str[enc_type], scheme_str[ts.SCHEME_TYPE.CKKS], poly_mod, coeff_mod_bit_sizes, \"Public key\", convert_size(len(ser))])\n",
    "  \n",
    "        ser = context.serialize(save_public_key=False, save_secret_key=True, save_galois_keys=False, save_relin_keys=False)\n",
    "        ctx_size_benchmarks.append([enc_type_str[enc_type], scheme_str[ts.SCHEME_TYPE.CKKS], poly_mod, coeff_mod_bit_sizes, \"Secret key\",  convert_size(len(ser))])\n",
    "                                    \n",
    "        ser = context.serialize(save_public_key=False, save_secret_key=False, save_galois_keys=True, save_relin_keys=False)\n",
    "        ctx_size_benchmarks.append([enc_type_str[enc_type], scheme_str[ts.SCHEME_TYPE.CKKS], poly_mod, coeff_mod_bit_sizes, \"Galois keys\",  convert_size(len(ser))])\n",
    "                                                                      \n",
    "        ser = context.serialize(save_public_key=False, save_secret_key=False, save_galois_keys=False, save_relin_keys=True)\n",
    "        ctx_size_benchmarks.append([enc_type_str[enc_type], scheme_str[ts.SCHEME_TYPE.CKKS], poly_mod, coeff_mod_bit_sizes, \"Relin keys\",  convert_size(len(ser))])\n",
    "  \n",
    "        ser = context.serialize(save_public_key=False, save_secret_key=False, save_galois_keys=False, save_relin_keys=False)\n",
    "        ctx_size_benchmarks.append([enc_type_str[enc_type], scheme_str[ts.SCHEME_TYPE.CKKS], poly_mod, coeff_mod_bit_sizes, \"none\", convert_size(len(ser))])\n",
    "        \n",
    "    for (poly_mod, coeff_mod_bit_sizes) in [\n",
    "        (8192, [40, 21, 21, 21, 21, 21, 21, 40]),\n",
    "        (8192, [40, 21, 21, 21, 21, 21, 40]),\n",
    "        (8192, [40, 21, 21, 21, 21, 40]),\n",
    "        (8192, [40, 21, 21, 21, 40]),\n",
    "        (8192, [40, 21, 21, 40]),\n",
    "        (8192, [40, 20, 40]),\n",
    "        (4096, [40, 20, 40]),\n",
    "        (4096, [30, 20, 30]),\n",
    "        (4096, [20, 20, 20]),\n",
    "        (4096, [19, 19, 19]),\n",
    "        (4096, [18, 18, 18]),\n",
    "        (2048, [20, 20]),\n",
    "    ]:\n",
    "        context = ts.context(\n",
    "            scheme=ts.SCHEME_TYPE.BFV,\n",
    "            poly_modulus_degree=poly_mod,\n",
    "            plain_modulus=786433,\n",
    "            coeff_mod_bit_sizes=coeff_mod_bit_sizes,\n",
    "            encryption_type=enc_type,\n",
    "        )\n",
    "        \n",
    "        context.generate_galois_keys()\n",
    "        context.generate_relin_keys()\n",
    "        \n",
    "        ser = context.serialize(save_public_key=True, save_secret_key=True, save_galois_keys=True, save_relin_keys=True)\n",
    "        ctx_size_benchmarks.append([enc_type_str[enc_type], scheme_str[ts.SCHEME_TYPE.BFV], poly_mod, coeff_mod_bit_sizes, \"all\", convert_size(len(ser))])\n",
    "        \n",
    "        if enc_type is ts.ENCRYPTION_TYPE.ASYMMETRIC:\n",
    "            ser = context.serialize(save_public_key=True, save_secret_key=False, save_galois_keys=False, save_relin_keys=False)\n",
    "            ctx_size_benchmarks.append([enc_type_str[enc_type], scheme_str[ts.SCHEME_TYPE.BFV], poly_mod, coeff_mod_bit_sizes, \"Public key\", convert_size(len(ser))])\n",
    "  \n",
    "        ser = context.serialize(save_public_key=False, save_secret_key=True, save_galois_keys=False, save_relin_keys=False)\n",
    "        ctx_size_benchmarks.append([enc_type_str[enc_type], scheme_str[ts.SCHEME_TYPE.BFV], poly_mod, coeff_mod_bit_sizes, \"Secret key\",  convert_size(len(ser))])\n",
    "                                    \n",
    "        ser = context.serialize(save_public_key=False, save_secret_key=False, save_galois_keys=True, save_relin_keys=False)\n",
    "        ctx_size_benchmarks.append([enc_type_str[enc_type], scheme_str[ts.SCHEME_TYPE.BFV], poly_mod, coeff_mod_bit_sizes, \"Galois keys\",  convert_size(len(ser))])\n",
    "                                                                      \n",
    "        ser = context.serialize(save_public_key=False, save_secret_key=False, save_galois_keys=False, save_relin_keys=True)\n",
    "        ctx_size_benchmarks.append([enc_type_str[enc_type], scheme_str[ts.SCHEME_TYPE.BFV], poly_mod, coeff_mod_bit_sizes, \"Relin keys\",  convert_size(len(ser))])\n",
    "  \n",
    "        ser = context.serialize(save_public_key=False, save_secret_key=False, save_galois_keys=False, save_relin_keys=False)\n",
    "        ctx_size_benchmarks.append([enc_type_str[enc_type], scheme_str[ts.SCHEME_TYPE.BFV], poly_mod, coeff_mod_bit_sizes, \"none\", convert_size(len(ser))])\n",
    "        \n",
    "\n",
    "display(HTML(tabulate.tabulate(ctx_size_benchmarks, tablefmt='html')))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Context serialization interpretation\n",
    "\n",
    "Some key points here would be:\n",
    " - The symmetric encryption creates smaller contexts than the public key ones.\n",
    " - Decreasing the length of the coefficient modulus decreases the size of the context but also the depth of available multiplications.\n",
    " - Decreasing the coefficient modulus sizes reduces the context size, but impacts the precision as well (for CKKS).\n",
    " - Galois keys increase the context size only for public contexts (without the secret key). Send them only when you need to perform ciphertext rotations on the other end.\n",
    " - Relinearization keys increase the context size only for public contexts. Send them only when you need to perform multiplications on ciphertexts on the other end.\n",
    " - When we send the secret key, the Relinearization/Galois key can be regenerated on the other end without sending them."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ciphertext serialization\n",
    "\n",
    "We next review how different parameters impact the ciphertext serialization.\n",
    "\n",
    "The first observation here is that the symmetric/asymmetric encryption switch doesn't actually impact the size of the ciphertext, only of the context.\n",
    "\n",
    "We will review the benchmarks only for the asymmetric scenario."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Plain data size in bytes 8.8 KB\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<table>\n",
       "<tbody>\n",
       "<tr><td>Encryption Type</td><td>Scheme Type</td><td>Polynomial modulus</td><td>Coefficient modulus sizes       </td><td>Precision</td><td>Ciphertext serialized size</td><td>Encryption increase ratio</td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>229.87 KB                 </td><td>26.11                    </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>427.15 KB                 </td><td>48.51                    </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>427.21 KB                 </td><td>48.52                    </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>153.29 KB                 </td><td>17.41                    </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>104.71 KB                 </td><td>11.89                    </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[60, 60]                        </td><td>2**38    </td><td>128.13 KB                 </td><td>14.55                    </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[40, 40]                        </td><td>2**38    </td><td>92.13 KB                  </td><td>10.46                    </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>8192              </td><td>[17, 17]                        </td><td>2**15    </td><td>38.92 KB                  </td><td>4.42                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>78.97 KB                  </td><td>8.97                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>66.31 KB                  </td><td>7.53                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>53.4 KB                   </td><td>6.06                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[19, 19, 19]                    </td><td>2**35    </td><td>49.75 KB                  </td><td>5.65                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[18, 18, 18]                    </td><td>2**33    </td><td>47.12 KB                  </td><td>5.35                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[30, 30]                        </td><td>2**25    </td><td>34.25 KB                  </td><td>3.89                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[25, 25]                        </td><td>2**20    </td><td>30.75 KB                  </td><td>3.49                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[18, 18]                        </td><td>2**16    </td><td>23.78 KB                  </td><td>2.7                      </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>4096              </td><td>[17, 17]                        </td><td>2**15    </td><td>18.55 KB                  </td><td>2.11                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[20, 20]                        </td><td>2**18    </td><td>13.12 KB                  </td><td>1.49                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[18, 18]                        </td><td>2**16    </td><td>12.09 KB                  </td><td>1.37                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>ckks       </td><td>2048              </td><td>[16, 16]                        </td><td>2**14    </td><td>8.86 KB                   </td><td>1.01                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>-        </td><td>427.28 KB                 </td><td>48.53                    </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 40]    </td><td>-        </td><td>373.11 KB                 </td><td>42.38                    </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 21, 40]        </td><td>-        </td><td>318.61 KB                 </td><td>36.19                    </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 21, 40]            </td><td>-        </td><td>264.14 KB                 </td><td>30.0                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 21, 21, 40]                </td><td>-        </td><td>209.79 KB                 </td><td>23.83                    </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>8192              </td><td>[40, 20, 40]                    </td><td>-        </td><td>154.59 KB                 </td><td>17.56                    </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[40, 20, 40]                    </td><td>-        </td><td>79.04 KB                  </td><td>8.98                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[30, 20, 30]                    </td><td>-        </td><td>66.37 KB                  </td><td>7.54                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[20, 20, 20]                    </td><td>-        </td><td>53.46 KB                  </td><td>6.07                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[19, 19, 19]                    </td><td>-        </td><td>49.8 KB                   </td><td>5.66                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>4096              </td><td>[18, 18, 18]                    </td><td>-        </td><td>47.05 KB                  </td><td>5.34                     </td></tr>\n",
       "<tr><td>asymmetric     </td><td>bfv        </td><td>2048              </td><td>[20, 20]                        </td><td>-        </td><td>13.03 KB                  </td><td>1.48                     </td></tr>\n",
       "</tbody>\n",
       "</table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "data = [random.uniform(-10, 10) for _ in range(10 ** 3)]\n",
    "network_data = pickle.dumps(data)\n",
    "print(\"Plain data size in bytes {}\".format(convert_size(len(network_data))))\n",
    "\n",
    "enc_type = ts.ENCRYPTION_TYPE.ASYMMETRIC\n",
    "ct_size_benchmarks = [[\"Encryption Type\", \"Scheme Type\", \"Polynomial modulus\", \"Coefficient modulus sizes\", \"Precision\", \"Ciphertext serialized size\", \"Encryption increase ratio\"]]\n",
    "\n",
    "\n",
    "for (poly_mod, coeff_mod_bit_sizes, prec) in [\n",
    "    (8192, [60, 40, 60], 40),\n",
    "    (8192, [40, 21, 21, 21, 21, 21, 21, 40], 40),\n",
    "    (8192, [40, 21, 21, 21, 21, 21, 21, 40], 21),\n",
    "    (8192, [40, 20, 40], 40),\n",
    "    (8192, [20, 20, 20], 38),\n",
    "    (8192, [60, 60], 38),\n",
    "    (8192, [40, 40], 38),\n",
    "    (8192, [17, 17], 15),\n",
    "    (4096, [40, 20, 40], 40),\n",
    "    (4096, [30, 20, 30], 40),\n",
    "    (4096, [20, 20, 20], 38),\n",
    "    (4096, [19, 19, 19], 35),\n",
    "    (4096, [18, 18, 18], 33),\n",
    "    (4096, [30, 30], 25),\n",
    "    (4096, [25, 25], 20),\n",
    "    (4096, [18, 18], 16),\n",
    "    (4096, [17, 17], 15),\n",
    "    (2048, [20, 20], 18),\n",
    "    (2048, [18, 18], 16),\n",
    "    (2048, [16, 16], 14),\n",
    "]:\n",
    "    context = ts.context(\n",
    "        scheme=ts.SCHEME_TYPE.CKKS,\n",
    "        poly_modulus_degree=poly_mod,\n",
    "        coeff_mod_bit_sizes=coeff_mod_bit_sizes,\n",
    "        encryption_type=enc_type,\n",
    "    )\n",
    "    scale = 2 ** prec\n",
    "    ckks_vec = ts.ckks_vector(context, data, scale)\n",
    " \n",
    "    enc_network_data = ckks_vec.serialize()\n",
    "    ct_size_benchmarks.append([enc_type_str[enc_type], scheme_str[ts.SCHEME_TYPE.CKKS], poly_mod, coeff_mod_bit_sizes, \"2**{}\".format(prec),convert_size(len(enc_network_data)), round(len(enc_network_data) / len(network_data), 2)])\n",
    "    \n",
    "for (poly_mod, coeff_mod_bit_sizes) in [\n",
    "    (8192, [40, 21, 21, 21, 21, 21, 21, 40]),\n",
    "    (8192, [40, 21, 21, 21, 21, 21, 40]),\n",
    "    (8192, [40, 21, 21, 21, 21, 40]),\n",
    "    (8192, [40, 21, 21, 21, 40]),\n",
    "    (8192, [40, 21, 21, 40]),\n",
    "    (8192, [40, 20, 40]),\n",
    "    (4096, [40, 20, 40]),\n",
    "    (4096, [30, 20, 30]),\n",
    "    (4096, [20, 20, 20]),\n",
    "    (4096, [19, 19, 19]),\n",
    "    (4096, [18, 18, 18]),\n",
    "    (2048, [20, 20]),\n",
    "]:\n",
    "    context = ts.context(\n",
    "        scheme=ts.SCHEME_TYPE.BFV,\n",
    "        poly_modulus_degree=poly_mod,\n",
    "        plain_modulus=786433,\n",
    "        coeff_mod_bit_sizes=coeff_mod_bit_sizes,\n",
    "        encryption_type=enc_type,\n",
    "    )\n",
    "    vec = ts.bfv_vector(context, data)\n",
    "    enc_network_data = vec.serialize()\n",
    "    ct_size_benchmarks.append([enc_type_str[enc_type], scheme_str[ts.SCHEME_TYPE.BFV], poly_mod, coeff_mod_bit_sizes, \"-\",convert_size(len(enc_network_data)), round(len(enc_network_data) / len(network_data), 2)])\n",
    "\n",
    "    \n",
    "display(HTML(tabulate.tabulate(ct_size_benchmarks, tablefmt='html')))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Ciphertext serialization interpretation\n",
    "\n",
    "Some observations are:\n",
    " - The polynomial modulus increase results in a ciphertext increase.\n",
    " - The length of coefficient modulus sizes impacts the ciphertext size.\n",
    " - The values of the coefficient modulus sizes impact the ciphertext size, as well as the precision.\n",
    " - For a fixed set of polynomial modulus and coefficient modulus sizes, changing the precision doesn't affect the ciphertext size."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Understanding the ciphertext precision impact\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table>\n",
       "<tbody>\n",
       "<tr><td>Value range  </td><td>Polynomial modulus</td><td>Coefficient modulus sizes       </td><td>Precision</td><td>Operation</td><td>Status                  </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -28</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -27</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -29</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>encrypt  </td><td>decryption prec 2 ** -11</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>sum      </td><td>decryption prec 2 ** -10</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -29</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[60, 60]                        </td><td>2**38    </td><td>encrypt  </td><td>decryption prec 2 ** -26</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[60, 60]                        </td><td>2**38    </td><td>sum      </td><td>decryption prec 2 ** -25</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[40, 40]                        </td><td>2**38    </td><td>encrypt  </td><td>decryption prec 2 ** -31</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[40, 40]                        </td><td>2**38    </td><td>sum      </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>decryption prec 2 ** -5 </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -31</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -29</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -28</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>decryption prec 2 ** -28</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>sum      </td><td>decryption prec 2 ** -27</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[19, 19, 19]                    </td><td>2**35    </td><td>encrypt  </td><td>decryption prec 2 ** -24</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[19, 19, 19]                    </td><td>2**35    </td><td>sum      </td><td>decryption prec 2 ** -23</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[18, 18, 18]                    </td><td>2**33    </td><td>encrypt  </td><td>decryption prec 2 ** -23</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[18, 18, 18]                    </td><td>2**33    </td><td>sum      </td><td>decryption prec 2 ** -22</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[30, 30]                        </td><td>2**25    </td><td>encrypt  </td><td>decryption prec 2 ** -18</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[30, 30]                        </td><td>2**25    </td><td>sum      </td><td>decryption prec 2 ** -17</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[25, 25]                        </td><td>2**20    </td><td>encrypt  </td><td>decryption prec 2 ** -9 </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[25, 25]                        </td><td>2**20    </td><td>sum      </td><td>decryption prec 2 ** -8 </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>decryption prec 2 ** -15</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>decryption prec 2 ** -6 </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>2048              </td><td>[20, 20]                        </td><td>2**18    </td><td>encrypt  </td><td>decryption prec 2 ** -9 </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>2048              </td><td>[20, 20]                        </td><td>2**18    </td><td>sum      </td><td>decryption prec 2 ** -8 </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>2048              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>decryption prec 2 ** -8 </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>2048              </td><td>[18, 18]                        </td><td>2**16    </td><td>sum      </td><td>decryption prec 2 ** -7 </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>2048              </td><td>[16, 16]                        </td><td>2**14    </td><td>encrypt  </td><td>decryption prec 2 ** -7 </td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -29</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -28</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -33</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -32</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>encrypt  </td><td>decryption prec 2 ** -11</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>sum      </td><td>decryption prec 2 ** -10</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -31</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[60, 60]                        </td><td>2**38    </td><td>encrypt  </td><td>decryption prec 2 ** -29</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[60, 60]                        </td><td>2**38    </td><td>sum      </td><td>decryption prec 2 ** -28</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[40, 40]                        </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -29</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -32</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -31</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>4096              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>4096              </td><td>[19, 19, 19]                    </td><td>2**35    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>4096              </td><td>[18, 18, 18]                    </td><td>2**33    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>4096              </td><td>[30, 30]                        </td><td>2**25    </td><td>encrypt  </td><td>decryption prec 2 ** -23</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>4096              </td><td>[30, 30]                        </td><td>2**25    </td><td>sum      </td><td>decryption prec 2 ** -22</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>4096              </td><td>[25, 25]                        </td><td>2**20    </td><td>encrypt  </td><td>decryption prec 2 ** -11</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>4096              </td><td>[25, 25]                        </td><td>2**20    </td><td>sum      </td><td>decryption prec 2 ** -10</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>4096              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>4096              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>2048              </td><td>[20, 20]                        </td><td>2**18    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>2048              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>2048              </td><td>[16, 16]                        </td><td>2**14    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -29</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -29</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -28</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>encrypt  </td><td>decryption prec 2 ** -13</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>sum      </td><td>decryption prec 2 ** -12</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>8192              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -29</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>8192              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -28</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>8192              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>8192              </td><td>[60, 60]                        </td><td>2**38    </td><td>encrypt  </td><td>decryption prec 2 ** -27</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>8192              </td><td>[60, 60]                        </td><td>2**38    </td><td>sum      </td><td>decryption prec 2 ** -26</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>8192              </td><td>[40, 40]                        </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>8192              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -32</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -31</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -31</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>4096              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>4096              </td><td>[19, 19, 19]                    </td><td>2**35    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>4096              </td><td>[18, 18, 18]                    </td><td>2**33    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>4096              </td><td>[30, 30]                        </td><td>2**25    </td><td>encrypt  </td><td>decryption prec 2 ** -15</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>4096              </td><td>[30, 30]                        </td><td>2**25    </td><td>sum      </td><td>decryption prec 2 ** -14</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>4096              </td><td>[25, 25]                        </td><td>2**20    </td><td>encrypt  </td><td>decryption prec 2 ** -10</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>4096              </td><td>[25, 25]                        </td><td>2**20    </td><td>sum      </td><td>decryption prec 2 ** -9 </td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>4096              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>4096              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>2048              </td><td>[20, 20]                        </td><td>2**18    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>2048              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>2048              </td><td>[16, 16]                        </td><td>2**14    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -32</td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -31</td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -31</td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>encrypt  </td><td>decryption prec 2 ** -12</td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>sum      </td><td>decryption prec 2 ** -11</td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>8192              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -29</td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>8192              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -28</td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>8192              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>8192              </td><td>[60, 60]                        </td><td>2**38    </td><td>encrypt  </td><td>decryption prec 2 ** -27</td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>8192              </td><td>[60, 60]                        </td><td>2**38    </td><td>sum      </td><td>decryption prec 2 ** -26</td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>8192              </td><td>[40, 40]                        </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>8192              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -29</td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -29</td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>4096              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>4096              </td><td>[19, 19, 19]                    </td><td>2**35    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>4096              </td><td>[18, 18, 18]                    </td><td>2**33    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>4096              </td><td>[30, 30]                        </td><td>2**25    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>4096              </td><td>[25, 25]                        </td><td>2**20    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>4096              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>4096              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>2048              </td><td>[20, 20]                        </td><td>2**18    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>2048              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>2048              </td><td>[16, 16]                        </td><td>2**14    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -28</td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -27</td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -32</td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -31</td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>encrypt  </td><td>decryption prec 2 ** -13</td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>sum      </td><td>decryption prec 2 ** -12</td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>8192              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -31</td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>8192              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>8192              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>8192              </td><td>[60, 60]                        </td><td>2**38    </td><td>encrypt  </td><td>decryption prec 2 ** -31</td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>8192              </td><td>[60, 60]                        </td><td>2**38    </td><td>sum      </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>8192              </td><td>[40, 40]                        </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>8192              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -32</td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -31</td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>4096              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>4096              </td><td>[19, 19, 19]                    </td><td>2**35    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>4096              </td><td>[18, 18, 18]                    </td><td>2**33    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>4096              </td><td>[30, 30]                        </td><td>2**25    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>4096              </td><td>[25, 25]                        </td><td>2**20    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>4096              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>4096              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>2048              </td><td>[20, 20]                        </td><td>2**18    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>2048              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>2048              </td><td>[16, 16]                        </td><td>2**14    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -31</td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -31</td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -30</td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>encrypt  </td><td>decryption prec 2 ** -9 </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>sum      </td><td>decryption prec 2 ** -8 </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>8192              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>8192              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>8192              </td><td>[60, 60]                        </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>8192              </td><td>[40, 40]                        </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>8192              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>4096              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>4096              </td><td>[19, 19, 19]                    </td><td>2**35    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>4096              </td><td>[18, 18, 18]                    </td><td>2**33    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>4096              </td><td>[30, 30]                        </td><td>2**25    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>4096              </td><td>[25, 25]                        </td><td>2**20    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>4096              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>4096              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>2048              </td><td>[20, 20]                        </td><td>2**18    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>2048              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>2048              </td><td>[16, 16]                        </td><td>2**14    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -39</td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -39</td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -39</td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -39</td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>encrypt  </td><td>decryption prec 2 ** -10</td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>sum      </td><td>decryption prec 2 ** -9 </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>8192              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>8192              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>8192              </td><td>[60, 60]                        </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>8192              </td><td>[40, 40]                        </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>8192              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>4096              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>4096              </td><td>[19, 19, 19]                    </td><td>2**35    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>4096              </td><td>[18, 18, 18]                    </td><td>2**33    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>4096              </td><td>[30, 30]                        </td><td>2**25    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>4096              </td><td>[25, 25]                        </td><td>2**20    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>4096              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>4096              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>2048              </td><td>[20, 20]                        </td><td>2**18    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>2048              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^41 - 2^42]</td><td>2048              </td><td>[16, 16]                        </td><td>2**14    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -39</td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>8192              </td><td>[60, 40, 60]                    </td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -39</td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>encrypt  </td><td>decryption prec 2 ** -39</td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**40    </td><td>sum      </td><td>decryption prec 2 ** -39</td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>encrypt  </td><td>decryption prec 2 ** -20</td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>8192              </td><td>[40, 21, 21, 21, 21, 21, 21, 40]</td><td>2**21    </td><td>sum      </td><td>decryption prec 2 ** -20</td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>8192              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>8192              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>8192              </td><td>[60, 60]                        </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>8192              </td><td>[40, 40]                        </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>8192              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>4096              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>4096              </td><td>[19, 19, 19]                    </td><td>2**35    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>4096              </td><td>[18, 18, 18]                    </td><td>2**33    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>4096              </td><td>[30, 30]                        </td><td>2**25    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>4096              </td><td>[25, 25]                        </td><td>2**20    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>4096              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>4096              </td><td>[17, 17]                        </td><td>2**15    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>2048              </td><td>[20, 20]                        </td><td>2**18    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>2048              </td><td>[18, 18]                        </td><td>2**16    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^51 - 2^52]</td><td>2048              </td><td>[16, 16]                        </td><td>2**14    </td><td>encrypt  </td><td>encryption failed       </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[60, 40, 40, 60]                </td><td>2**40    </td><td>mul      </td><td>decryption prec 2 ** -23</td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[40, 21, 21, 40]                </td><td>2**21    </td><td>mul      </td><td>decryption prec 2 ** -3 </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[40, 20, 20, 40]                </td><td>2**40    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>8192              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[20, 20, 20]                    </td><td>2**38    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[19, 19, 19]                    </td><td>2**35    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[18, 18, 18]                    </td><td>2**33    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[30, 30, 30]                    </td><td>2**25    </td><td>mul      </td><td>decryption prec 2 ** 0  </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[25, 25, 25]                    </td><td>2**20    </td><td>mul      </td><td>decryption prec 2 ** 0  </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>4096              </td><td>[18, 18, 18]                    </td><td>2**16    </td><td>mul      </td><td>decryption prec 2 ** -1 </td></tr>\n",
       "<tr><td>[2^-1 - 2^0] </td><td>2048              </td><td>[18, 18, 18]                    </td><td>2**16    </td><td>mul      </td><td>decryption prec 2 ** -1 </td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[60, 40, 40, 60]                </td><td>2**40    </td><td>mul      </td><td>decryption prec 2 ** -21</td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[40, 21, 21, 40]                </td><td>2**21    </td><td>mul      </td><td>decryption prec 2 ** 0  </td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>8192              </td><td>[40, 20, 20, 40]                </td><td>2**40    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^0 - 2^1]  </td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>8192              </td><td>[60, 40, 40, 60]                </td><td>2**40    </td><td>mul      </td><td>decryption prec 2 ** -19</td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>8192              </td><td>[40, 20, 20, 40]                </td><td>2**40    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^1 - 2^2]  </td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>8192              </td><td>[60, 40, 40, 60]                </td><td>2**40    </td><td>mul      </td><td>decryption prec 2 ** -11</td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>8192              </td><td>[40, 20, 20, 40]                </td><td>2**40    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^5 - 2^6]  </td><td>4096              </td><td>[30, 20, 30]                    </td><td>2**40    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>8192              </td><td>[60, 40, 40, 60]                </td><td>2**40    </td><td>mul      </td><td>decryption prec 2 ** 0  </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>8192              </td><td>[40, 20, 20, 40]                </td><td>2**40    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^11 - 2^12]</td><td>4096              </td><td>[40, 20, 40]                    </td><td>2**40    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "<tr><td>[2^21 - 2^22]</td><td>8192              </td><td>[40, 20, 20, 40]                </td><td>2**40    </td><td>mul      </td><td>failed                  </td></tr>\n",
       "</tbody>\n",
       "</table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "data = [ random.random()]\n",
    "\n",
    "enc_type = ts.ENCRYPTION_TYPE.ASYMMETRIC\n",
    "ct_size_benchmarks = [[\"Value range\", \"Polynomial modulus\", \"Coefficient modulus sizes\", \"Precision\", \"Operation\", \"Status\"]]\n",
    "\n",
    "\n",
    "for data_pow in [-1, 0, 1, 5, 11, 21, 41, 51]:\n",
    "    data = [ random.uniform(2 ** data_pow, 2 ** (data_pow + 1))]\n",
    "    for (poly_mod, coeff_mod_bit_sizes, prec) in [\n",
    "        (8192, [60, 40, 60], 40),\n",
    "        (8192, [40, 21, 21, 21, 21, 21, 21, 40], 40),\n",
    "        (8192, [40, 21, 21, 21, 21, 21, 21, 40], 21),\n",
    "        (8192, [40, 20, 40], 40),\n",
    "        (8192, [20, 20, 20], 38),\n",
    "        (8192, [60, 60], 38),\n",
    "        (8192, [40, 40], 38),\n",
    "        (8192, [17, 17], 15),\n",
    "        (4096, [40, 20, 40], 40),\n",
    "        (4096, [30, 20, 30], 40),\n",
    "        (4096, [20, 20, 20], 38),\n",
    "        (4096, [19, 19, 19], 35),\n",
    "        (4096, [18, 18, 18], 33),\n",
    "        (4096, [30, 30], 25),\n",
    "        (4096, [25, 25], 20),\n",
    "        (4096, [18, 18], 16),\n",
    "        (4096, [17, 17], 15),\n",
    "        (2048, [20, 20], 18),\n",
    "        (2048, [18, 18], 16),\n",
    "        (2048, [16, 16], 14),\n",
    "    ]:\n",
    "        val_str = \"[2^{} - 2^{}]\".format(data_pow, data_pow + 1)\n",
    "        context = ts.context(\n",
    "            scheme=ts.SCHEME_TYPE.CKKS,\n",
    "            poly_modulus_degree=poly_mod,\n",
    "            coeff_mod_bit_sizes=coeff_mod_bit_sizes,\n",
    "            encryption_type=enc_type,\n",
    "        )\n",
    "        scale = 2 ** prec\n",
    "        try:\n",
    "            ckks_vec = ts.ckks_vector(context, data, scale)\n",
    "        except BaseException as e:\n",
    "            ct_size_benchmarks.append([val_str, poly_mod, coeff_mod_bit_sizes, \"2**{}\".format(prec), \"encrypt\", \"encryption failed\"])\n",
    "            continue\n",
    "    \n",
    "        decrypted = decrypt(ckks_vec)\n",
    "        for dec_prec in reversed(range(prec)):\n",
    "            if pytest.approx(decrypted, abs=2 ** -dec_prec) == data:\n",
    "                ct_size_benchmarks.append([val_str, poly_mod, coeff_mod_bit_sizes, \"2**{}\".format(prec), \"encrypt\", \"decryption prec 2 ** {}\".format(-dec_prec)])\n",
    "                break\n",
    "        ckks_sum = ckks_vec + ckks_vec\n",
    "        decrypted = decrypt(ckks_sum)\n",
    "        for dec_prec in reversed(range(prec)):\n",
    "            if pytest.approx(decrypted, abs=2 ** -dec_prec) == [data[0] + data[0]]:\n",
    "                ct_size_benchmarks.append([val_str, poly_mod, coeff_mod_bit_sizes, \"2**{}\".format(prec), \"sum\", \"decryption prec 2 ** {}\".format(-dec_prec)])\n",
    "                break\n",
    "                \n",
    "\n",
    "# We add more depth for the multiplication scenario\n",
    "for data_pow in [-1, 0, 1, 5, 11, 21, 41, 51]:\n",
    "    data = [ random.uniform(2 ** data_pow, 2 ** (data_pow + 1))]\n",
    "    for (poly_mod, coeff_mod_bit_sizes, prec) in [\n",
    "        (8192, [60, 40, 40, 60], 40),\n",
    "        (8192, [40, 21, 21, 40], 40),\n",
    "        (8192, [40, 21, 21, 40], 21),\n",
    "        (8192, [40, 20, 20, 40], 40),\n",
    "        (8192, [20, 20, 20], 38),\n",
    "        (4096, [40, 20, 40], 40),\n",
    "        (4096, [30, 20, 30], 40),\n",
    "        (4096, [20, 20, 20], 38),\n",
    "        (4096, [19, 19, 19], 35),\n",
    "        (4096, [18, 18, 18], 33),\n",
    "        (4096, [30, 30, 30], 25),\n",
    "        (4096, [25, 25, 25], 20),\n",
    "        (4096, [18, 18, 18], 16),\n",
    "        (2048, [18, 18, 18], 16),\n",
    "    ]:\n",
    "        val_str = \"[2^{} - 2^{}]\".format(data_pow, data_pow + 1)\n",
    "        context = ts.context(\n",
    "            scheme=ts.SCHEME_TYPE.CKKS,\n",
    "            poly_modulus_degree=poly_mod,\n",
    "            coeff_mod_bit_sizes=coeff_mod_bit_sizes,\n",
    "            encryption_type=enc_type,\n",
    "        )\n",
    "        scale = 2 ** prec\n",
    "        try:\n",
    "            ckks_vec = ts.ckks_vector(context, data, scale)\n",
    "        except BaseException as e:\n",
    "            continue\n",
    "                \n",
    "        try:\n",
    "            ckks_mul = ckks_vec * ckks_vec\n",
    "        except:\n",
    "            ct_size_benchmarks.append([val_str, poly_mod, coeff_mod_bit_sizes, \"2**{}\".format(prec), \"mul\", \"failed\"])\n",
    "            continue\n",
    "        decrypted = decrypt(ckks_mul)\n",
    "        for dec_prec in reversed(range(prec)):\n",
    "            if pytest.approx(decrypted, abs=2 ** -dec_prec) == [data[0] * data[0]]:\n",
    "                ct_size_benchmarks.append([val_str, poly_mod, coeff_mod_bit_sizes, \"2**{}\".format(prec), \"mul\", \"decryption prec 2 ** {}\".format(-dec_prec)])\n",
    "                break\n",
    "                \n",
    "display(HTML(tabulate.tabulate(ct_size_benchmarks, tablefmt='html')))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Congratulations!!! - Time to Join the Community!\n",
    "\n",
    "Congratulations on completing this notebook tutorial! If you enjoyed this and would like to join the movement towards privacy preserving, decentralized ownership of AI and the AI supply chain (data), you can do so in the following ways!\n",
    "\n",
    "### Star TenSEAL on GitHub\n",
    "\n",
    "The easiest way to help our community is just by starring the Repos! This helps raise awareness of the cool tools we're building.\n",
    "\n",
    "- [Star TenSEAL](https://github.com/OpenMined/TenSEAL)\n",
    "\n",
    "### Join our Slack!\n",
    "\n",
    "The best way to keep up to date on the latest advancements is to join our community! You can do so by filling out the form at [http://slack.openmined.org](http://slack.openmined.org).\n",
    "\n",
    "### Donate\n",
    "\n",
    "If you don't have time to contribute to our codebase, but would still like to lend support, you can also become a Backer on our Open Collective. All donations go toward our web hosting and other community expenses such as hackathons and meetups!\n",
    "\n",
    "[OpenMined's Open Collective Page](https://opencollective.com/openmined)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## References\n",
    "\n",
    "1. Yongsoo Song, Introduction to CKKS, [Private AI Bootcamp](microsoft.com/en-us/research/event/private-ai-bootcamp/#!videos).\n",
    "2. [Microsoft SEAL](https://github.com/microsoft/SEAL).\n",
    "3. Daniel Huynh, [CKKS Explained Series](https://blog.openmined.org/ckks-explained-part-1-simple-encoding-and-decoding/)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.6 (default, Sep 26 2022, 11:37:49) \n[Clang 14.0.0 (clang-1400.0.29.202)]"
  },
  "vscode": {
   "interpreter": {
    "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
